/* ------------------------------------------------------------------------- */
 // File       : LensFlare.cpp
 // Project    : Long Forgotten Earth
 // Author     : David de Lorenzo
 /* ------------------------------------------------------------------------- */

#include "LensFlare.h"

using namespace Ogre;

int LensFlare::nextID = 0;

 /* ------------------------------------------------------------------------- */
 /// Constructor
 /// @param LightPosition The 3D position of the Light, relative to the camera.
 /// @param camera        The camera on which the lensflare effect will appear.
 /// @param SceneMgr      Pointer on the SceneManager.
 /* ------------------------------------------------------------------------- */
 LensFlare::LensFlare(Vector3 LightPosition, Camera* camera, SceneManager* SceneMgr, Real scale)
 {
    mId = ++nextID;
 	mSceneMgr      = SceneMgr;
 	mCamera        = camera;
 	mHidden        = true;
 	this->createLensFlare(scale);
 	this->setLightPosition(LightPosition);
 }

 /* ------------------------------------------------------------------------- */
 /// Destructor
 /* ------------------------------------------------------------------------- */
 LensFlare::~LensFlare()
 {
 	mNode->detachObject(mHaloSet);
 	mNode->detachObject(mBurstSet);
// 	mSceneMgr->removeBillboardSet(mHaloSet);
// 	mSceneMgr->removeBillboardSet(mBurstSet);
 	/// TODO destroy mNode
 }


 /* ------------------------------------------------------------------------- */
 /// this function creates and shows all the LensFlare graphical elements.
 /* ------------------------------------------------------------------------- */
 void LensFlare::createLensFlare(Real scale)
 {
 	Real LF_scale = scale;

 	// -----------------------------------------------------
 	// We create 2 sets of billboards for the lensflare
 	// -----------------------------------------------------
 	String idStr = StringConverter::toString(mId);

    mHaloSet = mSceneMgr->createBillboardSet("halo"+idStr);
 	mHaloSet->setMaterialName("lensflare/halo");
// 	mHaloSet->setCullIndividually(true);
// 	mHaloSet->setQueryFlags(VOIDOBJECT);	// They should not be detected by rays.

 	mBurstSet= mSceneMgr->createBillboardSet("burst"+idStr);
 	mBurstSet->setMaterialName("lensflare/burst");
// 	mBurstSet->setCullIndividually(true);
// 	mBurstSet->setQueryFlags(VOIDOBJECT);

 	// The node is located at the light source.
 	mNode  = mSceneMgr->getRootSceneNode()->createChildSceneNode("LensFlare"+idStr);

 	mNode->attachObject(mBurstSet);
 	mNode->attachObject(mHaloSet);



 	// -------------------------------
 	// Creation of the Halo billboards
 	// -------------------------------
 	Billboard* LF_Halo1 = mHaloSet->createBillboard(0,0,0);
 	LF_Halo1->setDimensions(LF_scale*0.5,LF_scale*0.5);
 	Billboard* LF_Halo2 = mHaloSet->createBillboard(0,0,0);
 	LF_Halo2->setDimensions(LF_scale,LF_scale);
 	Billboard* LF_Halo3 = mHaloSet->createBillboard(0,0,0);
 	LF_Halo3->setDimensions(LF_scale*0.25,LF_scale*0.25);


 	// -------------------------------
 	// Creation of the "Burst" billboards
 	// -------------------------------
 	Billboard* LF_Burst1 = mBurstSet->createBillboard(0,0,0);
 	LF_Burst1->setDimensions(LF_scale*0.5,LF_scale*0.5);
 	Billboard* LF_Burst2 = mBurstSet->createBillboard(0,0,0);
 	LF_Burst2->setDimensions(LF_scale*0.5,LF_scale*0.5);
 	Billboard* LF_Burst3 = mBurstSet->createBillboard(0,0,0);
 	LF_Burst3->setDimensions(LF_scale*0.5,LF_scale*0.5);

 }


 /* -------------------------------------------------------------------------- */
 /// This function updates the lensflare effect.
 /** This function should be called by your frameListener.
 */
 /* -------------------------------------------------------------------------- */
 void LensFlare::update()
{
   // If the Light is out of the Camera field Of View, the lensflare is hidden.
   if (!mCamera->isVisible(mLightPosition))
   {
      mHaloSet->setVisible(false);
      mBurstSet->setVisible(false);
      return;
   }
   else
   {
      mHaloSet->setVisible(true);
      mBurstSet->setVisible(true);
   }

   Real LightDistance  = mLightPosition.distance(mCamera->getDerivedPosition());
//   Real LightDistance  = mLightPosition.distance(mCamera->getPosition());
//   Vector3 CameraVect  = mCamera->getDirection(); // normalized vector (length 1)
   Vector3 CameraVect  = mCamera->getDerivedOrientation() * Vector3::UNIT_Z;

   CameraVect *= LightDistance;


   // The LensFlare effect takes place along this vector.
   Vector3 LFvect = (CameraVect - mLightPosition);
//   LFvect += Vector3(-512,-512,0);  // sprite dimension (to be adjusted, but not necessary)

   // The different sprites are placed along this line.

   mHaloSet->getBillboard(0)->setPosition( LFvect*0.500);
   mHaloSet->getBillboard(1)->setPosition( LFvect*0.125);
   mHaloSet->getBillboard(2)->setPosition(-LFvect*0.250);

   mBurstSet->getBillboard(0)->setPosition( LFvect*0.333);
   mBurstSet->getBillboard(1)->setPosition(-LFvect*0.500);
   mBurstSet->getBillboard(2)->setPosition(-LFvect*0.180);

   // We redraw the lensflare (in case it was previouly out of the camera field, and hidden)
   this->setVisible(true);
}


 /* ------------------------------------------------------------------------- */
 /// This function shows (or hide) the lensflare effect.
 /* ------------------------------------------------------------------------- */
 void LensFlare::setVisible(bool visible)
 {
 	mHaloSet->setVisible(visible);
 	mBurstSet->setVisible(visible);
 	mHidden = !visible;
 }


 /* ------------------------------------------------------------------------- */
 /// This function updates the light source position.
 /** This function can be used if the light source is moving.*/
 /* ------------------------------------------------------------------------- */
 void LensFlare::setLightPosition(Vector3 pos)
 {
 	mLightPosition = pos;
 	mNode->setPosition(mLightPosition);
 }


 /* ------------------------------------------------------------------------- */
 /// This function changes the colour of the burst.
 /* ------------------------------------------------------------------------- */
 void LensFlare::setBurstColour(ColourValue color)
 {
 	mBurstSet->getBillboard(0)->setColour(color);
 	mBurstSet->getBillboard(1)->setColour(color*0.8);
 	mBurstSet->getBillboard(2)->setColour(color*0.6);
 }

 /* ------------------------------------------------------------------------- */
 /// This function changes the colour of the halos.
 /* ------------------------------------------------------------------------- */
 void LensFlare::setHaloColour(ColourValue color)
 {
 	mHaloSet->getBillboard(0)->setColour(color*0.8);
 	mHaloSet->getBillboard(1)->setColour(color*0.6);
 	mHaloSet->getBillboard(2)->setColour(color);
 }


 bool LensFlare::frameStarted(const Ogre::FrameEvent &evt) {

    Node* sun = mSceneMgr->getRootSceneNode()->getChild("Sun");

//    sun->setPosition(sun->getPosition() + Vector3::NEGATIVE_UNIT_Y*10);
    Vector3 sunPos = sun->getPosition();


    setLightPosition(sunPos);
    update();

    return true;
 }

